﻿namespace DCHealthCheck.MvcWeb.Classes.DataServices {

    #region Usings
    using DCHealthCheck.Common;
    using DCHealthCheck.DomainModel;
    using DCHealthCheck.MvcWeb.Classes.ViewModels;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading;
    using System.Web;
    using System.Web.Mvc;
    #endregion

    public class ReplicationNeighborDataService : BaseDataService, IReplicationNeighborDataService {

        #region Members
        private readonly IRepository<ReplicationNeighbor, IEntityManager> ReplicationNeighborRepository;

        private readonly Expression<Func<ReplicationNeighbor, object>>[] ReplicationNeighborIncludedEntities;
        #endregion

        #region Constructor
        public ReplicationNeighborDataService(
            IRepository<DomainController, IEntityManager> dcRepository,
            IRepository<ReplicationNeighbor, IEntityManager> replicationNeighborRepository)
            : base(dcRepository) {
            if (replicationNeighborRepository == null) {
                throw new ArgumentNullException("replicationNeighborRepository");
            }

            this.ReplicationNeighborRepository = replicationNeighborRepository;
            this.ReplicationNeighborIncludedEntities = new Expression<Func<ReplicationNeighbor, object>>[] {
                (x) => x.SystemInfo,
                (x) => x.SystemInfo.DomainController
            };
        }
        #endregion

        #region Methods
        private void BuildFilterSelectLists(ReplicationNeighborViewModel viewModel) {
            var filteredDCIds = this.GetFilteredReplicationNeighbors(viewModel)
                .Select(x => x.SystemInfo.DomainController.Id)
                .Distinct()
                .ToList();

            base.BuildFilterSelectLists(filteredDCIds, viewModel);

            var selectListItem = new SelectListItem();
            selectListItem.Text = "(Any)";
            selectListItem.Value = string.Empty;

            viewModel.SourceServerSelectListItems.Add(selectListItem);
            viewModel.PartitionNameSelectListItems.Add(selectListItem);
            viewModel.ReplicationReasonSelectListItems.Add(selectListItem);

            var sourceServers = new List<string>();
            var partitionNames = new List<string>();
            var distinctReplicationReasons = new List<string>();
            var allReplicationReasons = new List<string>();
            var individualReplicationReasons = new Dictionary<string, int>();

            sourceServers = this.GetFilteredReplicationNeighbors(viewModel)
                .Select(x => x.SourceServer)
                .Distinct()
                .ToList();

            partitionNames = this.GetFilteredReplicationNeighbors(viewModel)
                .Select(x => x.PartitionName)
                .Distinct()
                .ToList();

            distinctReplicationReasons = this.GetFilteredReplicationNeighbors(viewModel)
                .Select(x => x.ReplicationReason)
                .Distinct()
                .ToList();

            allReplicationReasons = this.GetFilteredReplicationNeighbors(viewModel)
                .Select(x => x.ReplicationReason)
                .ToList();

            foreach (var serverName in sourceServers) {
                selectListItem = new SelectListItem();
                selectListItem.Text = serverName;
                if (!string.IsNullOrWhiteSpace(viewModel.SourceServer) && string.Equals(viewModel.SourceServer, serverName, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = serverName;
                viewModel.SourceServerSelectListItems.Add(selectListItem);
            }

            foreach (var partitionName in partitionNames) {
                selectListItem = new SelectListItem();
                selectListItem.Text = partitionName;
                if (!string.IsNullOrWhiteSpace(viewModel.PartitionName) && string.Equals(viewModel.PartitionName, partitionName, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = partitionName;
                viewModel.PartitionNameSelectListItems.Add(selectListItem);
            }

            // Parse the individual reasons from the comma-separated values
            // Example: RING_TOPOLOGY, MINIMIZE_HOPS_TOPOLOGY
            foreach (var replicationReason in distinctReplicationReasons) {
                var individualReasons = replicationReason.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var reason in individualReasons) {
                    if (!individualReplicationReasons.ContainsKey(reason)) {
                        individualReplicationReasons.Add(reason, 0);
                    }
                }
            }

            foreach (var reason in individualReplicationReasons.Keys.ToList()) {
                individualReplicationReasons[reason] = allReplicationReasons.Count(x => x.Contains(reason));
                selectListItem = new SelectListItem();
                selectListItem.Text = string.Format("{0} ({1})", reason, individualReplicationReasons[reason]);
                if (!string.IsNullOrWhiteSpace(viewModel.ReplicationReason) && string.Equals(viewModel.ReplicationReason, reason, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = reason;
                viewModel.ReplicationReasonSelectListItems.Add(selectListItem);
            }
        }

        private IQueryable<ReplicationNeighbor> GetFilteredReplicationNeighbors(ReplicationNeighborViewModel viewModel) {

            var replicationNeighbors = this.ReplicationNeighborRepository.Get(this.ReplicationNeighborIncludedEntities);

            if (viewModel.SystemInfoId != Guid.Empty) {
                replicationNeighbors = replicationNeighbors.Where(x => x.SystemInfo.Id == viewModel.SystemInfoId);
            }
            else {
                if (viewModel.DomainControllerId != Guid.Empty) {
                    replicationNeighbors = replicationNeighbors.Where(x => x.SystemInfo.DomainController.Id == viewModel.DomainControllerId);
                }

                if (viewModel.Date != DateTime.MinValue) {
                    replicationNeighbors = replicationNeighbors.Where(x => x.SystemInfo.CheckDateTimeUTC == viewModel.Date);
                }
                else {
                    if (viewModel.StartDate.HasValue) {
                        replicationNeighbors = replicationNeighbors.Where(x => x.SystemInfo.CheckDateUTC >= viewModel.StartDate);
                    }
                    if (viewModel.EndDate.HasValue) {
                        replicationNeighbors = replicationNeighbors.Where(x => x.SystemInfo.CheckDateUTC <= viewModel.EndDate);
                    }
                }

                if (!string.IsNullOrWhiteSpace(viewModel.ADSite)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.SystemInfo.DomainController.ADSite == viewModel.ADSite);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.Domain)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.SystemInfo.DomainController.NetbiosDomain == viewModel.Domain);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.OSVersion)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.SystemInfo.DomainController.OSVersion == viewModel.OSVersion);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.DCName)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.SystemInfo.DomainController.SamAccountName == viewModel.DCName);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.SourceServer)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.SourceServer == viewModel.SourceServer);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.PartitionName)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.PartitionName == viewModel.PartitionName);
                }
                if (!string.IsNullOrWhiteSpace(viewModel.ReplicationReason)) {
                    replicationNeighbors = replicationNeighbors
                        .Where(x => x.ReplicationReason.Contains(viewModel.ReplicationReason));
                }
            } // else if (this.SystemInfoId != Guid.Empty)

            return replicationNeighbors;
        }

        public void ProcessData(ReplicationNeighborViewModel viewModel) {
            Global.DefaultLog.DebugFormat("[ThreadId: {0}] {1}", Thread.CurrentThread.ManagedThreadId, Extensions.CurrentMethodName());

            try {
                viewModel.Initialize();
                var replicationNeighbors = this.GetFilteredReplicationNeighbors(viewModel);
                viewModel.DisplayTotalResults = replicationNeighbors.Count();

                #region Skip count, take, and sorting
                if (!string.IsNullOrWhiteSpace(viewModel.SortColumn)) {
                    if (viewModel.CurrentSortDirection == System.Web.Helpers.SortDirection.Ascending) {
                        viewModel.ReplicationNeighbors = replicationNeighbors
                            .OrderBy(viewModel.SortColumn)
                            .Skip(viewModel.SkipCount.Value)
                            .Take(viewModel.TakeCount.Value)
                            .ToList();
                    }
                    else {
                        viewModel.ReplicationNeighbors = replicationNeighbors
                            .OrderByDescending(viewModel.SortColumn)
                            .Skip(viewModel.SkipCount.Value)
                            .Take(viewModel.TakeCount.Value)
                            .ToList();
                    }
                }
                else {
                    viewModel.ReplicationNeighbors = replicationNeighbors
                        .OrderBy(x => x.SystemInfo.DomainController.SamAccountName)
                        .Skip(viewModel.SkipCount.Value)
                        .Take(viewModel.TakeCount.Value)
                        .ToList();
                }
                #endregion

                viewModel.GetPageCounts();
                this.BuildFilterSelectLists(viewModel);
            }
            catch (Exception e) {
                Global.DefaultLog.DebugFormat("[ThreadId: {0}] {1} {2}", Thread.CurrentThread.ManagedThreadId, Extensions.CurrentMethodName(), e.VerboseExceptionString());
            }
        }
        #endregion
    }
}